﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Linq;

namespace DataServices.Services
{
    public class RestfullServices : IRestfullServices
    {
        private bool disposed;
        public RestfullServices()
        {
        }
        /// <summary>
        /// Set Base Address with base Uri
        /// </summary>
        /// <param name="baseUri">string baseUri</param>
        public void SetBaseAddress(string baseUri)
        {
            BaseUri = new Uri(baseUri);
            HttpClient = CreateHttpClient(BaseUri);
        }

        /// Gets or sets BaseUri 
        /// </summary>
        public Uri BaseUri { get; private set; }

        protected HttpClient HttpClient { get; set; }

        public virtual void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        ///     <see cref="IRestfulHttpClient" />
        /// </summary>
        public async Task<string> GetAsync(string servicePath, IDictionary<string, string> parms)
        {
            HttpResponseMessage httpResponseMessage = null;
            string dataRuturn = null;
            if (parms == null)
            {
                httpResponseMessage = await SendAsync(HttpMethod.Get, servicePath);
            }
            else
            {

                httpResponseMessage = await SendAsync(HttpMethod.Get, servicePath + "?" + ConstructQueryParameters(parms));
            }
            if (httpResponseMessage.IsSuccessStatusCode)
                dataRuturn = await httpResponseMessage.Content.ReadAsStringAsync();
            return dataRuturn;
        }

        /// <summary>
        ///     <see cref="IRestfulHttpClient" />
        /// </summary>
        public async Task<string> PostAsync(string servicePath, IDictionary<string, string> parms)
        {
            string data = null;
            HttpResponseMessage responseMessage=null;
            if(parms!=null)
                responseMessage = await PostAsync(servicePath, ConstructQueryParameters(parms));
            else
                responseMessage = await PostAsync(servicePath, string.Empty);

            if (responseMessage.IsSuccessStatusCode)
            {
                data = await responseMessage.Content.ReadAsStringAsync();
            }
            Debug.WriteLine(data);
            return data;
        }
        /// <summary>
        ///     <see cref="IRestfulHttpClient" />
        /// </summary>
        public async Task<HttpResponseMessage> PostAsync(string servicePath, string parms)
        {
            var httpContent = new StringContent(parms);

            HttpResponseMessage responseMessage =
                await SendStringContentAsync(HttpMethod.Post, servicePath, httpContent);

            return responseMessage;
        }

        private HttpClient CreateHttpClient(Uri baseUri)
        {
            CreateHttpClient().BaseAddress = baseUri;

            return HttpClient;
        }

        private HttpClient CreateHttpClient()
        {
            var handler = new HttpClientHandler();
            if (handler.SupportsAutomaticDecompression)
            {
                handler.AutomaticDecompression = DecompressionMethods.GZip;
            }
            HttpClient = new HttpClient(handler);

            //// There might be a case of cache authentication data so we need to prevent those case by set 
            //// no-cache on the request header
            var cacheControl = new CacheControlHeaderValue();
            cacheControl.NoCache = true;
            HttpClient.DefaultRequestHeaders.CacheControl = cacheControl;
            return HttpClient;
        }

        public async Task<HttpResponseMessage> SendAsync(HttpMethod httpMethod, string servicePath)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("The HttpClient Resource was disposed.");
            }
            var requestMessage = new HttpRequestMessage(httpMethod, servicePath);
            HttpResponseMessage responseMessage = null;
            try
            {
                responseMessage = await HttpClient.SendAsync(requestMessage).ConfigureAwait(false);

                // Skipped check for BadRequest Error
                if (responseMessage.StatusCode != HttpStatusCode.BadRequest)
                {
                    responseMessage.EnsureSuccessStatusCode();
                }
            }
            catch (Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex);
#endif
            }

            return responseMessage;
        }

        public async Task<HttpResponseMessage> SendStringContentAsync(HttpMethod httpMethod, string servicePath, StringContent httpContent)
        {
            if (disposed)
            {
                throw new ObjectDisposedException("The HttpClient Resource was disposed.");
            }
            httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
            var requestMessage = new HttpRequestMessage(httpMethod, servicePath) { Content = httpContent };
           
            HttpResponseMessage responseMessage = null;
            try
            {
                responseMessage = await HttpClient.SendAsync(requestMessage).ConfigureAwait(false);

                // Skipped check for BadRequest Error
                if (responseMessage.StatusCode != HttpStatusCode.BadRequest)
                {
                    responseMessage.EnsureSuccessStatusCode();
                }
            }
            catch (Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex);
#endif
            }

            return responseMessage;
        }

        protected string ConstructQueryParameters(IDictionary<string, string> parms)
        {
            var requestContent = new FormUrlEncodedContent(parms);
            return requestContent.ReadAsStringAsync().Result;
        }


        protected string ConstructFilterParameters(IDictionary<string, string> parms)
        {
            var items = new List<string>();

            string queryParameters = String.Join(";", items.ToArray());
            return queryParameters;
        }

        private void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    if (HttpClient != null)
                    {
                        HttpClient.Dispose();
                    }
                }

                HttpClient = null;
                disposed = true;
            }
        }
        private string DictionaryToJson(IDictionary<string, string> dict)
        {
            var entries = dict.Select(d =>
                string.Format("\"{0}\": [{1}]", d.Key, string.Join(",", d.Value)));
            return "{" + string.Join(",", entries) + "}";
        }
    }
}
